#include "fdecode.h"
#include<string>
#include <iostream>
#include<fstream>
#include<iterator>
#include"constants.h"
#include<sstream>

using namespace std;

bits::bits()
{
    isjump=0;
    value=0;
    notop=0;
    immediate=0;
    op1=-1;
    op2=-1;
    destination=-1;
    target=-1;
    return;
}
string bits::registernum(bitset<5> dat)
{
    stringstream temp;

    temp<<"R"<<dat.to_ulong();
    return temp.str();
}
string bits::unumber(bitset<5> dat)
{
    stringstream temp;
    temp<<dat.to_ulong();
    immediate=dat.to_ulong();
    return temp.str();

}
string bits::immediatec()
{
    bitset <16> im;
    stringstream temp;
    temp.flush();
    int i=15,j;
    for(j=4;j>-1;j--,i--)
        {
        im[i]=rd[j];
        }

        for(j=4;j>-1;j--,i--)
        {
            im[i]=shamt[j];
        }
    
         for(j=5;j>-1;j--,i--)
        {
             im[i]=funct[j];
        }
    if(im[15]==1)
    {

        //int *dummy=new int;
        //delete dummy;
        im.flip();
        immediate= -1* ((long)im.to_ulong()+1);

        temp<<"#-"<<(long)im.to_ulong()+1;
        im.flip();
    }
    else
    {
        immediate=(long)im.to_ulong();
        temp<<"#"<<(long)im.to_ulong();
    }
        return temp.str();

}
string bits::unsigned_immediate()
{

}
string bits::offset()
{
    bitset <18> im;
    stringstream temp;
    temp.flush();
    int i=17,j;
    for(j=4;j>-1;j--,i--)
        {
        im[i]=rd[j];
        }

        for(j=4;j>-1;j--,i--)
        {
            im[i]=shamt[j];
        }

         for(j=5;j>-1;j--,i--)
        {
             im[i]=funct[j];
        }
    
    if(im[17]!=1)
    {temp<<"#"<<(long)im.to_ulong(); target=address+4+(long)im.to_ulong();}
    else
    {
        im.flip();
        temp<<"#-"<<(long)im.to_ulong()+1;
        target=address+4-(long)im.to_ulong()+1;
        im.flip();
    }

    return temp.str();
}
string bits::baseoffset()
{
    bitset <16> im;
    stringstream temp;
    temp.flush();
    int i=15,j;
    for(j=4;j>-1;j--,i--)
        {
          im[i]=rd[j];
        }

        for(j=4;j>-1;j--,i--)
        {
                 im[i]=shamt[j];
        }

         for(j=5;j>-1;j--,i--)
        {
                    im[i]=funct[j];
        }
        temp<<(long)im.to_ulong()<<"("<<registernum(rs)<<")";
        
        immediate=im.to_ulong();
    return temp.str();
}
string bits::instrindex()
{
    bitset <26> im;
    stringstream temp;
    temp.flush();
    int i=25,j;
    for(j=4;j>-1;j--,i--)
        {
        //cout<<i<<" " << j << " " <<rd[j] <<endl;
        im[i]=rs[j];
        }
    for(j=4;j>-1;j--,i--)
        {
        //cout<<i<<" " << j << " " <<rd[j] <<endl;
        im[i]=rt[j];
        }
    for(j=4;j>-1;j--,i--)
        {
        //cout<<i<<" " << j << " " <<rd[j] <<endl;
        im[i]=rd[j];
        }

        for(j=4;j>-1;j--,i--)
        {
        //cout<<i<<" " << j<< " " <<shamt[j] <<endl;
            im[i]=shamt[j];
        }

         for(j=5;j>-1;j--,i--)
        {
        //cout<<i<<" " << j<< " " <<funct[j] <<endl;
             im[i]=funct[j];
        }
   // cout<<endl<<im<<endl;
    temp<<"#"<<(long)im.to_ulong()*4;
    target=(long)im.to_ulong()*4;
    return temp.str();
}
void bits::allreg()
{
    Rs.assign(registernum(rd));
    destination=rd.to_ulong();
    Rt.assign(registernum(rs));
    op1=rs.to_ulong();
    Rd.assign(registernum(rt));
    op2=rt.to_ulong();
}
void bits::regimm()
{
    if( rd==BGEZ)
    {
        opcode.assign("BGEZ");
        Rs.assign(registernum(rs));
        op1=rs.to_ulong();
        Rd.assign(offset());
        isjump=1;
    }
    if( rd ==BLTZ)
    {
        
    opcode.assign("BLTZ");
        Rs.assign(registernum(rs));
        op1=rs.to_ulong();
        Rd.assign(offset());
        isjump=1;
    }
}
void bits::clear()
{
    Rt.clear();
    Rs.clear();
    Rd.clear();
    rt.reset();
    rs.reset();
    rd.reset();
    shamt.reset();
    funct.reset();
    op.reset();
    value=0;
    notop=0;
}
void bits::disassemble()
{
    if(breakencounter)
    {
        notop=1;
        if(raw[31]==1)
        { 
            value=(raw.flip().to_ulong()+1);raw.flip();
        if(value>0)
            value=value*-1;
        }
        else
            value=raw.to_ulong();
        opcode.assign(string("DATA"));
        return;
    }
    if(op.none()&&rt.none()&&rs.none()&&rd.none()&&shamt.none()&&funct.none())
    {
        opcode.assign(string("NOP"));

        return;
    }

    if(!op.any())//special
    {
        special();
    }
    else if(op==REGIMM)
    {
        regimm();
    }
    else if(op==ADDI)
    {
        opcode.assign(string("ADDI"));
        Rs.assign(registernum(rs));
        op1=rs.to_ulong();
        Rt.assign(registernum(rt));
        destination=rt.to_ulong();
        Rd.assign(immediatec());

    }
    else if (op==ADDIU)
    {
        opcode.assign(string("ADDIU"));
        Rs.assign(registernum(rs));
        op1=rs.to_ulong();
        Rt.assign(registernum(rt));
        destination=rt.to_ulong();
        Rd.assign(immediatec());
    }
    else if(op==BEQ)
    {
        opcode.assign(string("BEQ"));
        Rs.assign(registernum(rs));
        op1=rs.to_ulong();
        Rt.assign(registernum(rt));
        op2=rt.to_ulong();
        Rd.assign(offset());
        isjump=1;
    }
    
  
    else if(op==BGTZ)
    {
        opcode.assign(string("BGTZ"));
        Rs.assign(registernum(rs));
        op1=rs.to_ulong();
        //Rt.assign(registernum(rt));
        Rd.assign(offset());
        isjump=1;
    }
     else if(op==BLEZ)
    {
        opcode.assign(string("BLEZ"));
        Rs.assign(registernum(rs));
        op1=rs.to_ulong();
        //Rt.assign(registernum(rt));
        Rd.assign(offset());
        isjump=1;
    }
    else if(op==BNE)
    {
        opcode.assign(string("BNE"));
        Rs.assign(registernum(rs));
        op1=rs.to_ulong();
        Rt.assign(registernum(rt));
        op2=rt.to_ulong();
        Rd.assign(offset());
        isjump=1;
    }
    
    else if(op==J)
    {
    opcode.assign(string("J"));
        Rd.assign(instrindex());
        //Rt.assign(registernum(rt));
        //Rd.assign(offset());
        isjump=1;
    }
    else if(op==LW)
    {
            opcode.assign(string("LW"));
        //Rs.assign(registernum(rs));
        Rt.assign(registernum(rt));
        destination=rt.to_ulong();
        op1=rs.to_ulong();
        Rd.assign(baseoffset());
    }
    
   
    else if (op==SW)
    {
     opcode.assign(string("SW"));
        //Rs.assign(registernum(rs));
        Rt.assign(registernum(rt));

        op1=rt.to_ulong();
        Rd.assign(baseoffset());
        op2=rs.to_ulong();
    }
    else if(op==SLTI)
    {
        opcode.assign(string("SLTI"));
        Rs.assign(registernum(rs));
        op1=rs.to_ulong();
        Rt.assign(registernum(rt));
        destination=rt.to_ulong();
        Rd.assign(immediatec());
    }
}
void bits::special()
{
if(funct==ADD)
{
    opcode.assign(string ("ADD"));
    allreg();
}
else if(funct==ADDU)
{
    opcode.assign(string ("ADDU"));
    allreg();
}
else if(funct==AND)
{
    opcode.assign(string ("AND"));
    allreg();
}
else if(funct==BREAK)
{
    opcode.assign(string ("BREAK"));
    breakencounter=1;
}
else if(funct==NOR)
{
    opcode.assign(string ("NOR"));
    allreg();
}

else if(funct==OR)
{
    opcode.assign(string ("OR"));
    allreg();
}
else if(funct==SLL&&rs.none())
{
    opcode.assign(string ("SLL"));
    Rs.assign(registernum(rd));
    destination=rd.to_ulong();
    Rt.assign(registernum(rt));
    op1=rt.to_ulong();
    Rd.assign(string("#").append(unumber(shamt)));

}
else if(funct==SLT)
{
    opcode.assign(string ("SLT"));
    allreg();
}
else if(funct==SLTU)
{
    opcode.assign(string ("SLTU"));
    allreg();
}

else if(funct==SRA&&rs.none())
{
    opcode.assign(string ("SRA"));
    Rs.assign(registernum(rd));
    destination=rd.to_ulong();
    Rt.assign(registernum(rt));
    op1=rt.to_ulong();
    Rd.assign(unumber(shamt));

}
else if(funct==SRL&&rs.none())
{
    opcode.assign(string ("SRL"));
    Rs.assign(registernum(rd));
    destination=rd.to_ulong();
    Rt.assign(registernum(rt));
    op1=rt.to_ulong();
    Rd.assign(unumber(shamt));

}
else if(funct==SUB)
{
    opcode.assign(string ("SUB"));
    allreg();
}
else if(funct==SUBU)
{
    opcode.assign(string ("SUBU"));
    allreg();
}
else if(funct==XOR)
{
    opcode.assign(string ("XOR"));
    allreg();
}
}



int bits::read(int addr)
{
    if (!inputf.is_open()||inputf.eof())
        return 0;
        address=addr;
     bitset <32> temp;
     bitset <32> readcorrect;

    //cout<<sizeof(a);
    inputf.read((char*)&temp,4);
    int i,j;
    for (i=0,j=24;i<8;i++,j++)
    {
        readcorrect[j]=temp[i];
    }
    for (i=8,j=16;i<16;i++,j++)
    {
        readcorrect[j]=temp[i];
    }
    for (i=16,j=8;i<24;i++,j++)
    {
        readcorrect[j]=temp[i];
    }
    for (i=24,j=0;i<32;i++,j++)
    {
        readcorrect[j]=temp[i];
    }
    raw=readcorrect;

    i=31;
    for (j=5;j>=0;j--,i--)
        op[j]=readcorrect[i];
    for (j=4;j>=0;j--,i--)
        rs[j]=readcorrect[i];
    for (j=4;j>=0;j--,i--)
        rt[j]=readcorrect[i];
    for (j=4;j>=0;j--,i--)
        rd[j]=readcorrect[i];
    for (j=4;j>=0;j--,i--)
        shamt[j]=readcorrect[i];
     for (j=5;j>=0;j--,i--)
        funct[j]=readcorrect[i];
    //cout << op==string() << "T?F ";

//cout <<op <<" "<< rs << " " << rt << " "<< rd << " " << shamt <<" " << funct <<endl<<bitset<4>(string("1101"))<<endl;
   return 1;
}
void bits::print()
{
    
    if(! (opcode==string("DATA"))||opcode==string("BREAK"))
    {
    outputf <<op <<" "<< rs << " " << rt << " "<< rd << " " << shamt <<" " << funct ;
     outputf<<" "<<address<<" " <<opcode<<" ";
     cout<<address<<" "<<opcode;
     if(opcode.compare(string("ADDI"))==0||opcode.compare(string("ADDIU"))==0)
     {
         outputf<<Rt<<", "<<Rs<<", "<<Rd<<endl;
         cout<<Rt<<", "<<Rs<<", "<<Rd<<endl;
         return;
     }
     if(!Rs.empty())
     {    outputf<< Rs<<", "; cout<< Rs<<", ";}

     if(!Rt.empty())
     {   outputf<<  Rt<<", "; cout<<  Rt<<", ";}
      if(!Rd.empty())
      {   outputf<<Rd<<""; cout<<Rd<<"";}
      outputf<<endl; cout<<endl;

    }
    else
    {
        outputf <<op << rs <<  rt <<  rd <<  shamt << funct << " "<<address<<" "<<value <<endl;
    }
    
}
void bits::fprint()
{

    if(! (opcode==string("DATA"))||opcode==string("BREAK"))
    {
        cout<<address<<" "<<opcode<< " ";
     if(opcode.compare(string("ADDI"))==0||opcode.compare(string("ADDIU"))==0)
     {

         cout<<Rt<<", "<<Rs<<", "<<Rd;
         return;
     }
     if(!Rs.empty())
     {    cout<< Rs<<", ";}

     if(!Rt.empty())
     {   cout<<  Rt<<", ";}
      if(!Rd.empty())
      {   cout<<Rd<<"";}


    }
    else
    {
        cout<<opcode;
    }

}
int bits::gettarget()
{
    return target;
}

void mInsert (int addr,bits instruction )
{
    mMemory[addr]=instruction;
}


  